﻿using System;
using System.Collections.Generic;
using System.Text;

namespace Efficient.Domain
{
    
    /// <summary>
    /// 用于对比2个集合中数据的差别
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class GenericDirtyEntitySet<T> : IGenericDirtyEntitySet<T>
    {
        private readonly List<T> rawEntityList;
        private readonly List<T> newEntityList;

        public GenericDirtyEntitySet(IEnumerable<T> rawData, IEnumerable<T> newData)
        {
            rawEntityList = new List<T>(rawData);
            newEntityList = new List<T>(newData);
        }

        /// <summary>
        /// 获取较之原来集合是新增加的数据
        /// </summary>
        /// <returns></returns>
        public IList<T> GetToBeInsert()
        {
            return GetToBeInsert(delegate(T rawItem, T newItem) { return rawItem.Equals(newItem); });
        }
        /// <summary>
        /// 获取较之原来集合是新增加的数据
        /// </summary>
        /// <param name="predicate">判断的条件委托</param>
        /// <returns></returns>
        public IList<T> GetToBeInsert(Func<T> predicate)
        {
            List<T> result = new List<T>(this.newEntityList.Count);
            List<T> localRaw = new List<T>(this.rawEntityList);
            foreach (T item in newEntityList)
            {
                T exist = localRaw.Find(delegate(T left)
                {
                    return predicate(left, item);
                });

                if (exist == null && !result.Contains(item))
                {
                    result.Add(item);
                }
                else
                {
                    localRaw.Remove(exist);
                }
            }
            return result;
        }

        /// <summary>
        /// 获取较之原来集合是应该被删除的数据
        /// </summary>
        /// <returns></returns>
        public IList<T> GetToBeDelete()
        {
            return GetToBeDelete(delegate(T rawItem, T newItem) { return rawItem.Equals(newItem); });
        }
        /// <summary>
        /// 获取较之原来集合是应该被删除的数据
        /// </summary>
        /// <param name="predicate">判断的条件委托</param>
        /// <returns></returns>
        public IList<T> GetToBeDelete(Func<T> predicate)
        {
            List<T> result = new List<T>(this.rawEntityList.Count);
            List<T> localNew = new List<T>(this.newEntityList);
            foreach (T item in rawEntityList)
            {
                T exist = localNew.Find(delegate(T left)
                {
                    return predicate(left, item);
                });
                if (exist == null && !result.Contains(item))
                {
                    result.Add(item);
                }
                else
                {
                    localNew.Remove(exist);
                }
            }
            return result;
        }

        public IList<T> GetToBeUpdate()
        {
            return GetToBeUpdate(delegate(T rawItem, T newItem) { return rawItem.Equals(newItem); });
        }

        /// <summary>
        /// 获取较之原来集合是应该被更新的数据
        /// </summary>
        /// <param name="predicate">判断的条件委托</param>
        /// <returns></returns>
        public IList<T> GetToBeUpdate(Func<T> predicate)
        {
            List<T> result = new List<T>(Math.Min(this.rawEntityList.Count, this.newEntityList.Count));
            List<T> localRaw = new List<T>(this.rawEntityList);
            foreach (T item in newEntityList)
            {
                T exist = localRaw.Find(delegate(T left)
                {
                    return predicate(left, item);
                });
                if (exist != null && !result.Contains(item))
                {
                    result.Add(item);
                    localRaw.Remove(item);
                }
                
            }
            return result;
        }
    }
}
